+2004-07-07 Matthias Clasen <mclasen@redhat.com>
+
+ Support separators in combo boxes and more generally in tree
+ views (#135873):
+
+ * gtk/gtkcombobox.h:
+ * gtk/gtkcombobox.c (gtk_combo_box_get_row_separator_column):
+ * gtk/gtkcombobox.c (gtk_combo_box_set_row_separator_column):
+ Add a ::row-separator-column property with getter and setter,
+ which can indicate a boolean model column to determine which
+ rows are separators.
+
+ * gtk/gtkcombobox.c: Display separator rows as separator menu
+ items in menu mode, and by using the new treeview separator
+ functionality in list mode.
+
+ * gtk/gtktreeview.h:
+ * gtk/gtktreeview.c (gtk_tree_view_get_row_separator_func):
+ * gtk/gtktreeview.c (gtk_tree_view_set_row_separator_func):
+ Add a callback to determine whether a row is a separator.
+
+ * gtk/gtktreeview.c (gtk_tree_view_bin_expose):
+ * gtk/gtktreeview.c (gtk_tree_view_create_row_drag_icon):
+ * gtk/gtktreeview.c (validate_row): Use the new callback
+ to determine whether a row is a separator, and draw it
+ as a separator then. Since separators should take up less
+ vertical space than regular rows, this requires removing
+ the redundant MAX(...,expander_size) calls which appear in
+ many places. Instead, the MAX() is now only done in
+ validate_row(), and only if the row is not a separator.
+ To catch possible side effects of this intrusive change,
+ I have left EXPANDER_MAX() calls in place of the MAX() calls
+ which will emit a warning if something breaks. They should
+ be removed before 2.6.
+
+ * gtk/gtktreeselection.c (row_is_selectable): Don't let
+ separator rows be selected.
+
+ * tests/testcombo.c (create_blaat): Add a separator column.
+
Tue Jul 6 22:58:00 2004 Matthias Clasen <maclas@gmx.de>
* gdk/x11/gdkwindow-x11.c (gdk_x11_window_set_user_time): Fix
+2004-07-07 Matthias Clasen <mclasen@redhat.com>
+
+ Support separators in combo boxes and more generally in tree
+ views (#135873):
+
+ * gtk/gtkcombobox.h:
+ * gtk/gtkcombobox.c (gtk_combo_box_get_row_separator_column):
+ * gtk/gtkcombobox.c (gtk_combo_box_set_row_separator_column):
+ Add a ::row-separator-column property with getter and setter,
+ which can indicate a boolean model column to determine which
+ rows are separators.
+
+ * gtk/gtkcombobox.c: Display separator rows as separator menu
+ items in menu mode, and by using the new treeview separator
+ functionality in list mode.
+
+ * gtk/gtktreeview.h:
+ * gtk/gtktreeview.c (gtk_tree_view_get_row_separator_func):
+ * gtk/gtktreeview.c (gtk_tree_view_set_row_separator_func):
+ Add a callback to determine whether a row is a separator.
+
+ * gtk/gtktreeview.c (gtk_tree_view_bin_expose):
+ * gtk/gtktreeview.c (gtk_tree_view_create_row_drag_icon):
+ * gtk/gtktreeview.c (validate_row): Use the new callback
+ to determine whether a row is a separator, and draw it
+ as a separator then. Since separators should take up less
+ vertical space than regular rows, this requires removing
+ the redundant MAX(...,expander_size) calls which appear in
+ many places. Instead, the MAX() is now only done in
+ validate_row(), and only if the row is not a separator.
+ To catch possible side effects of this intrusive change,
+ I have left EXPANDER_MAX() calls in place of the MAX() calls
+ which will emit a warning if something breaks. They should
+ be removed before 2.6.
+
+ * gtk/gtktreeselection.c (row_is_selectable): Don't let
+ separator rows be selected.
+
+ * tests/testcombo.c (create_blaat): Add a separator column.
+
Tue Jul 6 22:58:00 2004 Matthias Clasen <maclas@gmx.de>
* gdk/x11/gdkwindow-x11.c (gdk_x11_window_set_user_time): Fix
+2004-07-07 Matthias Clasen <mclasen@redhat.com>
+
+ Support separators in combo boxes and more generally in tree
+ views (#135873):
+
+ * gtk/gtkcombobox.h:
+ * gtk/gtkcombobox.c (gtk_combo_box_get_row_separator_column):
+ * gtk/gtkcombobox.c (gtk_combo_box_set_row_separator_column):
+ Add a ::row-separator-column property with getter and setter,
+ which can indicate a boolean model column to determine which
+ rows are separators.
+
+ * gtk/gtkcombobox.c: Display separator rows as separator menu
+ items in menu mode, and by using the new treeview separator
+ functionality in list mode.
+
+ * gtk/gtktreeview.h:
+ * gtk/gtktreeview.c (gtk_tree_view_get_row_separator_func):
+ * gtk/gtktreeview.c (gtk_tree_view_set_row_separator_func):
+ Add a callback to determine whether a row is a separator.
+
+ * gtk/gtktreeview.c (gtk_tree_view_bin_expose):
+ * gtk/gtktreeview.c (gtk_tree_view_create_row_drag_icon):
+ * gtk/gtktreeview.c (validate_row): Use the new callback
+ to determine whether a row is a separator, and draw it
+ as a separator then. Since separators should take up less
+ vertical space than regular rows, this requires removing
+ the redundant MAX(...,expander_size) calls which appear in
+ many places. Instead, the MAX() is now only done in
+ validate_row(), and only if the row is not a separator.
+ To catch possible side effects of this intrusive change,
+ I have left EXPANDER_MAX() calls in place of the MAX() calls
+ which will emit a warning if something breaks. They should
+ be removed before 2.6.
+
+ * gtk/gtktreeselection.c (row_is_selectable): Don't let
+ separator rows be selected.
+
+ * tests/testcombo.c (create_blaat): Add a separator column.
+
Tue Jul 6 22:58:00 2004 Matthias Clasen <maclas@gmx.de>
* gdk/x11/gdkwindow-x11.c (gdk_x11_window_set_user_time): Fix
+2004-07-07 Matthias Clasen <mclasen@redhat.com>
+
+ Support separators in combo boxes and more generally in tree
+ views (#135873):
+
+ * gtk/gtkcombobox.h:
+ * gtk/gtkcombobox.c (gtk_combo_box_get_row_separator_column):
+ * gtk/gtkcombobox.c (gtk_combo_box_set_row_separator_column):
+ Add a ::row-separator-column property with getter and setter,
+ which can indicate a boolean model column to determine which
+ rows are separators.
+
+ * gtk/gtkcombobox.c: Display separator rows as separator menu
+ items in menu mode, and by using the new treeview separator
+ functionality in list mode.
+
+ * gtk/gtktreeview.h:
+ * gtk/gtktreeview.c (gtk_tree_view_get_row_separator_func):
+ * gtk/gtktreeview.c (gtk_tree_view_set_row_separator_func):
+ Add a callback to determine whether a row is a separator.
+
+ * gtk/gtktreeview.c (gtk_tree_view_bin_expose):
+ * gtk/gtktreeview.c (gtk_tree_view_create_row_drag_icon):
+ * gtk/gtktreeview.c (validate_row): Use the new callback
+ to determine whether a row is a separator, and draw it
+ as a separator then. Since separators should take up less
+ vertical space than regular rows, this requires removing
+ the redundant MAX(...,expander_size) calls which appear in
+ many places. Instead, the MAX() is now only done in
+ validate_row(), and only if the row is not a separator.
+ To catch possible side effects of this intrusive change,
+ I have left EXPANDER_MAX() calls in place of the MAX() calls
+ which will emit a warning if something breaks. They should
+ be removed before 2.6.
+
+ * gtk/gtktreeselection.c (row_is_selectable): Don't let
+ separator rows be selected.
+
+ * tests/testcombo.c (create_blaat): Add a separator column.
+
Tue Jul 6 22:58:00 2004 Matthias Clasen <maclas@gmx.de>
* gdk/x11/gdkwindow-x11.c (gdk_x11_window_set_user_time): Fix
#include "gtkliststore.h"
#include "gtkmain.h"
#include "gtkmenu.h"
+#include "gtkseparatormenuitem.h"
#include "gtktearoffmenuitem.h"
#include "gtktogglebutton.h"
#include "gtktreeselection.h"
gint col_column;
gint row_column;
+ gint separator_column;
gint wrap_width;
PROP_WRAP_WIDTH,
PROP_ROW_SPAN_COLUMN,
PROP_COLUMN_SPAN_COLUMN,
+ PROP_ROW_SEPARATOR_COLUMN,
PROP_ACTIVE,
PROP_ADD_TEAROFFS
};
g_param_spec_int ("row_span_column",
P_("Row span column"),
P_("TreeModel column containing the row span values"),
- 0,
+ -1,
G_MAXINT,
- 0,
+ -1,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
g_param_spec_int ("column_span_column",
P_("Column span column"),
P_("TreeModel column containing the column span values"),
- 0,
+ -1,
G_MAXINT,
- 0,
+ -1,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_ROW_SEPARATOR_COLUMN,
+ g_param_spec_int ("row_separator_column",
+ P_("Row separator column"),
+ P_("Boolean TreeModel column specifying which rows are separators"),
+ -1,
+ G_MAXINT,
+ -1,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
combo_box->priv->active_item = -1;
combo_box->priv->col_column = -1;
combo_box->priv->row_column = -1;
+ combo_box->priv->separator_column = -1;
}
static void
gtk_combo_box_set_column_span_column (combo_box, g_value_get_int (value));
break;
+ case PROP_ROW_SEPARATOR_COLUMN:
+ gtk_combo_box_set_row_separator_column (combo_box, g_value_get_int (value));
+ break;
+
case PROP_ACTIVE:
gtk_combo_box_set_active (combo_box, g_value_get_int (value));
break;
g_value_set_int (value, combo_box->priv->col_column);
break;
+ case PROP_ROW_SEPARATOR_COLUMN:
+ g_value_set_int (value, combo_box->priv->separator_column);
+ break;
+
case PROP_ACTIVE:
g_value_set_int (value, gtk_combo_box_get_active (combo_box));
break;
GtkWidget *cell_view;
GList *cells, *list;
gboolean sensitive;
-
+
+ if (!GTK_IS_CELL_VIEW_MENU_ITEM (item))
+ return FALSE;
+
cell_view = gtk_bin_get_child (GTK_BIN (item));
gtk_cell_view_set_cell_data (GTK_CELL_VIEW (cell_view));
if (!combo_box->priv->column)
return TRUE;
+ if (combo_box->priv->separator_column != -1)
+ {
+ gboolean is_separator;
+
+ gtk_tree_model_get (combo_box->priv->model,
+ iter,
+ combo_box->priv->separator_column, &is_separator,
+ -1);
+
+ if (is_separator)
+ return FALSE;
+ }
+
gtk_tree_view_column_cell_set_cell_data (combo_box->priv->column,
combo_box->priv->model,
iter, FALSE, FALSE);
children = gtk_container_get_children (GTK_CONTAINER (menu));
child = children;
- if (child && GTK_IS_TEAROFF_MENU_ITEM (child->data))
- child = child->next;
-
for (i = 0; i < items; i++, child = child->next)
{
GtkWidget *item = GTK_WIDGET (child->data);
gboolean sensitive;
+ if (!GTK_IS_CELL_VIEW_MENU_ITEM (item))
+ continue;
+
sensitive = menu_row_is_sensitive (combo_box, item);
gtk_widget_set_sensitive (item, sensitive);
}
gtk_widget_show_all (combo_box->priv->popup_frame);
gtk_combo_box_list_position (combo_box, &x, &y, &width, &height);
-
+
gtk_widget_set_size_request (combo_box->priv->popup_window, width, -1);
gtk_window_move (GTK_WINDOW (combo_box->priv->popup_window), x, y);
}
gtk_combo_box_list_remove_grabs (combo_box);
+
gtk_widget_hide_all (combo_box->priv->popup_window);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
FALSE);
GdkEventScroll *event)
{
GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
- gint index;
- gint items;
+ gint index, new_index, items;
index = gtk_combo_box_get_active (combo_box);
items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
if (event->direction == GDK_SCROLL_UP)
- index--;
- else
- index++;
+ {
+ new_index = index - 1;
+ while (new_index >= 0 && !row_is_sensitive (combo_box, new_index))
+ new_index--;
+ if (new_index < 0)
+ new_index = index;
+ }
+ else
+ {
+ new_index = index + 1;
+ while (new_index < items && !row_is_sensitive (combo_box, new_index))
+ new_index++;
+ if (new_index == items)
+ new_index = index;
+ }
- gtk_combo_box_set_active (combo_box, CLAMP (index, 0, items - 1));
+ gtk_combo_box_set_active (combo_box, CLAMP (new_index, 0, items - 1));
}
return TRUE;
for (i = 0; i < items; i++)
{
GtkTreePath *path;
+ GtkTreeIter iter;
+ gboolean is_separator;
path = gtk_tree_path_new_from_indices (i, -1);
- tmp = gtk_cell_view_menu_item_new_from_model (combo_box->priv->model,
- path);
- g_signal_connect (tmp, "activate",
- G_CALLBACK (gtk_combo_box_menu_item_activate),
- combo_box);
- cell_view_sync_cells (combo_box,
- GTK_CELL_VIEW (GTK_BIN (tmp)->child));
+ if (combo_box->priv->separator_column != -1)
+ {
+ gtk_tree_model_get_iter (combo_box->priv->model, &iter, path);
+ gtk_tree_model_get (combo_box->priv->model, &iter,
+ combo_box->priv->separator_column, &is_separator, -1);
+ }
+ else
+ is_separator = FALSE;
+
+ if (is_separator)
+ tmp = gtk_separator_menu_item_new ();
+ else
+ {
+ tmp = gtk_cell_view_menu_item_new_from_model (combo_box->priv->model,
+ path);
+ g_signal_connect (tmp, "activate",
+ G_CALLBACK (gtk_combo_box_menu_item_activate),
+ combo_box);
+
+ cell_view_sync_cells (combo_box,
+ GTK_CELL_VIEW (GTK_BIN (tmp)->child));
+ }
gtk_menu_shell_append (GTK_MENU_SHELL (menu), tmp);
* list style
*/
+static gboolean
+row_is_separator (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ GtkComboBox *combo_box = GTK_COMBO_BOX (data);
+ gboolean is_separator = FALSE;
+
+ if (combo_box->priv->separator_column != -1)
+ gtk_tree_model_get (combo_box->priv->model, iter,
+ combo_box->priv->separator_column, &is_separator, -1);
+
+ return is_separator;
+}
+
static void
gtk_combo_box_list_setup (GtkComboBox *combo_box)
{
FALSE);
gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (combo_box->priv->tree_view),
TRUE);
-
+ gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (combo_box->priv->tree_view),
+ row_is_separator, combo_box, NULL);
if (combo_box->priv->model)
gtk_tree_view_set_model (GTK_TREE_VIEW (combo_box->priv->tree_view),
combo_box->priv->model);
g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
col = gtk_tree_model_get_n_columns (combo_box->priv->model);
- g_return_if_fail (row_span >= 0 && row_span < col);
+ g_return_if_fail (row_span >= -1 && row_span < col);
if (row_span != combo_box->priv->row_column)
{
g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
col = gtk_tree_model_get_n_columns (combo_box->priv->model);
- g_return_if_fail (column_span >= 0 && column_span < col);
+ g_return_if_fail (column_span >= -1 && column_span < col);
if (column_span != combo_box->priv->col_column)
{
g_object_notify (G_OBJECT (combo_box), "add_tearoffs");
}
}
+
+/**
+ * gtk_combo_box_set_row_separator_column:
+ * @combo_box: a #GtkComboBox
+ * @column: the index of a boolean model column, or -1 to
+ * turn off separators
+ *
+ * Sets the row separator column index.
+ * This model column contains boolean values which indicate
+ * whether a row is to be drawn as a separator or now.
+ * Setting the index to -1 turns off separators.
+ *
+ * Since: 2.6
+ **/
+void
+gtk_combo_box_set_row_separator_column (GtkComboBox *combo_box,
+ gint column)
+{
+ gint col;
+
+ g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
+ col = gtk_tree_model_get_n_columns (combo_box->priv->model);
+ g_return_if_fail (column >= -1 && column < col);
+
+ if (combo_box->priv->separator_column != column)
+ {
+ combo_box->priv->separator_column = column;
+
+ gtk_widget_queue_draw (combo_box);
+
+ g_object_notify (G_OBJECT (combo_box), "row_separator_column");
+ }
+}
+
+/**
+ * gtk_combo_box_get_row_separator_column:
+ * @combo_box: a #GtkComboBox
+ *
+ * Returns the current row separator column index.
+ *
+ * Return value: the row separator column index
+ *
+ * Since: 2.6
+ **/
+gint
+gtk_combo_box_get_row_separator_column (GtkComboBox *combo_box)
+{
+ g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), -1);
+
+ return combo_box->priv->separator_column;
+}
GtkTreeModel *model);
GtkTreeModel *gtk_combo_box_get_model (GtkComboBox *combo_box);
+void gtk_combo_box_set_row_separator_column (GtkComboBox *combo_box,
+ gint column);
+gint gtk_combo_box_get_row_separator_column (GtkComboBox *combo_box);
+
/* convenience -- text */
GtkWidget *gtk_combo_box_new_text (void);
void gtk_combo_box_append_text (GtkComboBox *combo_box,
GtkTreePath *path)
{
GList *list;
- gboolean sensitive;
-
- sensitive = FALSE;
+ GtkTreeIter iter;
+ gboolean sensitive = FALSE;
+
+ if (!gtk_tree_model_get_iter (selection->tree_view->priv->model, &iter, path))
+ sensitive = TRUE;
+
+ if (!sensitive && selection->tree_view->priv->row_separator_func)
+ {
+ /* never allow separators to be selected */
+ if ((* selection->tree_view->priv->row_separator_func) (selection->tree_view->priv->model,
+ &iter,
+ selection->tree_view->priv->row_separator_data))
+ return FALSE;
+ }
+
for (list = selection->tree_view->priv->columns; list && !sensitive; list = list->next)
{
GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (list->data);
- GtkTreeIter iter;
if (!column->visible)
continue;
- if (gtk_tree_model_get_iter (selection->tree_view->priv->model, &iter, path))
- sensitive = tree_column_is_sensitive (column, selection->tree_view->priv->model, &iter);
- else
- sensitive = TRUE;
+ sensitive = tree_column_is_sensitive (column, selection->tree_view->priv->model, &iter);
}
if (!sensitive)
#define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
#define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
+#define EXPANDER_MAX(height,expander_size,tree_view,tree,node) check_expander_max (height, expander_size, tree_view, tree, node)
+
typedef struct _GtkTreeViewChild GtkTreeViewChild;
struct _GtkTreeViewChild
gint wy,
gint *tx,
gint *ty);
+static gint check_expander_max (gint height,
+ gint expander_size,
+ GtkTreeView *tree_view,
+ GtkRBTree *tree,
+ GtkRBNode *node);
+
static GtkContainerClass *parent_class = NULL;
static guint tree_view_signals [LAST_SIGNAL] = { 0 };
tree_view->priv->search_user_data = NULL;
}
+ if (tree_view->priv->row_separator_destroy)
+ {
+ (* tree_view->priv->row_separator_destroy) (tree_view->priv->row_separator_data);
+ tree_view->priv->row_separator_data = NULL;
+ }
+
gtk_tree_view_set_model (tree_view, NULL);
if (GTK_OBJECT_CLASS (parent_class)->destroy)
path = _gtk_tree_view_find_path (tree_view, tree, node);
depth = gtk_tree_path_get_depth (path);
background_area.y = y_offset + event->y;
- background_area.height = MAX (GTK_RBNODE_GET_HEIGHT (node),
- tree_view->priv->expander_size);
+ background_area.height = EXPANDER_MAX (GTK_RBNODE_GET_HEIGHT (node),
+ tree_view->priv->expander_size,
+ tree_view, tree, node);
background_area.x = 0;
arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
- arrow.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
+ arrow.height = EXPANDER_MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size,
+ tree_view, tree, node);
gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
path);
depth = gtk_tree_path_get_depth (path);
gtk_tree_path_free (path);
-
+
cursor_path = NULL;
drag_dest_path = NULL;
gdk_drawable_get_size (tree_view->priv->bin_window,
&bin_window_width, NULL);
-
+
n_visible_columns = 0;
for (list = tree_view->priv->columns; list; list = list->next)
{
do
{
gboolean parity;
+ gboolean is_separator = FALSE;
+
+ if (tree_view->priv->row_separator_func)
+ {
+ is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model,
+ &iter,
+ tree_view->priv->row_separator_data);
+ }
- max_height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
+ max_height = EXPANDER_MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size,
+ tree_view, tree, node);
x_offset = -event->area.x;
cell_offset = 0;
* level of the tree we're dropping at.
*/
highlight_x = cell_area.x;
- _gtk_tree_view_column_cell_render (column,
- event->window,
- &background_area,
- &cell_area,
- &event->area,
- flags);
+ if (is_separator)
+ gtk_paint_hline (widget->style,
+ event->window,
+ state,
+ &cell_area,
+ widget,
+ NULL,
+ cell_area.x,
+ cell_area.x + cell_area.width,
+ cell_area.y + cell_area.height / 2);
+ else
+ _gtk_tree_view_column_cell_render (column,
+ event->window,
+ &background_area,
+ &cell_area,
+ &event->area,
+ flags);
if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
{
gint x, y;
}
else
{
- _gtk_tree_view_column_cell_render (column,
- event->window,
- &background_area,
- &cell_area,
- &event->area,
- flags);
+ if (is_separator)
+ gtk_paint_hline (widget->style,
+ event->window,
+ state,
+ &cell_area,
+ widget,
+ NULL,
+ cell_area.x,
+ cell_area.x + cell_area.width,
+ cell_area.y + cell_area.height / 2);
+ else
+ _gtk_tree_view_column_cell_render (column,
+ event->window,
+ &background_area,
+ &cell_area,
+ &event->area,
+ flags);
}
if (node == cursor && has_special_cell &&
((column == tree_view->priv->focus_column &&
"treeview-drop-indicator",
0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
- focus_line_width / 2,
- width, MAX(BACKGROUND_HEIGHT (node),
- tree_view->priv->expander_size)
+ width, EXPANDER_MAX(BACKGROUND_HEIGHT (node),
+ tree_view->priv->expander_size,
+ tree_view, tree, node)
- focus_line_width + 1);
break;
}
0,
BACKGROUND_FIRST_PIXEL (tree_view, tree, node),
width,
- MAX (BACKGROUND_HEIGHT (node),
- tree_view->priv->expander_size));
+ EXPANDER_MAX (BACKGROUND_HEIGHT (node),
+ tree_view->priv->expander_size,
+ tree_view, tree, node));
}
y_offset += max_height;
gint horizontal_separator;
gint depth = gtk_tree_path_get_depth (path);
gboolean retval = FALSE;
-
+ gboolean is_separator = FALSE;
+ gint focus_pad;
+
/* double check the row needs validating */
if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
return FALSE;
+ if (tree_view->priv->row_separator_func)
+ {
+ is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model,
+ iter,
+ tree_view->priv->row_separator_data);
+ }
+
gtk_widget_style_get (GTK_WIDGET (tree_view),
+ "focus-padding", &focus_pad,
"horizontal_separator", &horizontal_separator,
NULL);
-
+
for (list = tree_view->priv->columns; list; list = list->next)
{
gint tmp_width;
NULL, NULL, NULL,
&tmp_width, &tmp_height);
- height = MAX (height, tmp_height);
- height = MAX (height, tree_view->priv->expander_size);
+ if (!is_separator)
+ {
+ height = MAX (height, tmp_height);
+ height = MAX (height, tree_view->priv->expander_size);
+ }
+ else
+ height = 2 + 2 * focus_pad;
if (gtk_tree_view_is_expander_column (tree_view, column) && TREE_VIEW_DRAW_EXPANDERS (tree_view))
{
if (tree_view->priv->scroll_to_use_align)
{
- gint height = MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
+ gint height = EXPANDER_MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size,
+ tree_view, tree, node);
area_above = (total_height - height) *
tree_view->priv->scroll_to_row_align;
area_below = total_height - area_above - height;
* 2) row visible
*/
gint dy;
- gint height = MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
+ gint height = EXPANDER_MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size,
+ tree_view, tree, node);
dy = _gtk_rbtree_node_find_offset (tree, node);
size_changed = TRUE;
}
area_above = 0;
- area_below = total_height - MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
+ area_below = total_height - EXPANDER_MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size,
+ tree_view, tree, node);
}
above_path = gtk_tree_path_copy (path);
}
}
- area_below -= MAX (new_height, tree_view->priv->expander_size);
+ area_below -= EXPANDER_MAX (new_height, tree_view->priv->expander_size,
+ tree_view, tree, node);
}
gtk_tree_path_free (path);
area_above -= new_height - old_height;
}
}
- area_above -= MAX (new_height, tree_view->priv->expander_size);
+ area_above -= EXPANDER_MAX (new_height, tree_view->priv->expander_size,
+ tree_view, tree, node);
update_dy = TRUE;
}
gtk_tree_path_free (path);
- tree_view->priv->fixed_height = MAX (GTK_RBNODE_GET_HEIGHT (node),
- tree_view->priv->expander_size);
+ tree_view->priv->fixed_height = EXPANDER_MAX (GTK_RBNODE_GET_HEIGHT (node),
+ tree_view->priv->expander_size,
+ tree_view, tree, node);
}
_gtk_rbtree_set_fixed_height (tree_view->priv->tree,
{
gint height;
- height = MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
+ height = EXPANDER_MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size,
+ tree_view, tree, node);
if (prev_height < 0)
prev_height = height;
else if (prev_height != height)
return;
}
- if (MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size)
+ if (EXPANDER_MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size,
+ tree_view, tree, node)
< tree_view->priv->top_row_dy)
{
/* new top row -- do NOT install the idle handler */
rect.width = MAX (tree_view->priv->expander_size, GTK_WIDGET (tree_view)->allocation.width);
rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
- rect.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
+ rect.height = EXPANDER_MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size,
+ tree_view, tree, node);
if (clip_rect)
{
rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width);
rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
- rect.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
+ rect.height = EXPANDER_MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size,
+ tree_view, tree, node);
if (clip_rect)
{
y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
y += count * tree_view->priv->vadjustment->page_size;
if (count > 0)
- y -= MAX (GTK_RBNODE_GET_HEIGHT (cursor_node),
- tree_view->priv->expander_size);
+ y -= EXPANDER_MAX (GTK_RBNODE_GET_HEIGHT (cursor_node),
+ tree_view->priv->expander_size,
+ tree_view, cursor_tree, cursor_node);
else if (count < 0)
- y += MAX (GTK_RBNODE_GET_HEIGHT (cursor_node),
- tree_view->priv->expander_size);
+ y += EXPANDER_MAX (GTK_RBNODE_GET_HEIGHT (cursor_node),
+ tree_view->priv->expander_size,
+ tree_view, cursor_tree, cursor_node);
y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower, (gint)tree_view->priv->vadjustment->upper - vertical_separator);
if (y > tree_view->priv->height)
rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
- rect->height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
+ rect->height = EXPANDER_MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size,
+ tree_view, tree, node);
}
if (column)
gint x = 1, y = 1;
GdkDrawable *drawable;
gint bin_window_width;
+ gboolean is_separator = FALSE;
widget = GTK_WIDGET (tree_view);
&iter,
path))
return NULL;
+
+ if (tree_view->priv->row_separator_func)
+ {
+ is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model,
+ &iter,
+ tree_view->priv->row_separator_data);
+ }
cell_offset = x;
background_area.y = y;
- background_area.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
+ background_area.height = EXPANDER_MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size,
+ tree_view, tree, node);
gdk_drawable_get_size (tree_view->priv->bin_window,
&bin_window_width, NULL);
}
if (gtk_tree_view_column_cell_is_visible (column))
- _gtk_tree_view_column_cell_render (column,
- drawable,
- &background_area,
- &cell_area,
- &expose_area,
- 0);
+ {
+ if (is_separator)
+ gtk_paint_hline (widget->style,
+ drawable,
+ GTK_STATE_NORMAL,
+ &cell_area,
+ widget,
+ NULL,
+ cell_area.x,
+ cell_area.x + cell_area.width,
+ cell_area.y + cell_area.height / 2);
+ else
+ _gtk_tree_view_column_cell_render (column,
+ drawable,
+ &background_area,
+ &cell_area,
+ &expose_area,
+ 0);
+ }
cell_offset += column->width;
}
{
return tree_view->priv->hover_selection;
}
+
+
+/**
+ * gtk_tree_view_get_row_separator_func:
+ * @tree_view: a #GtkTreeView
+ *
+ * Returns the current row separator function.
+ *
+ * Return value: the current row separator function.
+ *
+ * Since: 2.6
+ **/
+GtkTreeViewRowSeparatorFunc
+gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
+
+ return tree_view->priv->row_separator_func;
+}
+
+/**
+ * gtk_tree_view_set_row_separator_func:
+ * @tree_view: a #GtkTreeView
+ * @func: a #GtkTreeRowSeparatorFunc
+ * @data: user data to pass to @func, or %NULL
+ * @destroy: destroy notifier for @data, or %NULL
+ *
+ * Sets the row separator function, which is used to determine
+ * whether a row should be drawn as a separator.
+ *
+ * Since: 2.6
+ **/
+void
+gtk_tree_view_set_row_separator_func (GtkTreeView *tree_view,
+ GtkTreeViewRowSeparatorFunc func,
+ gpointer data,
+ GtkDestroyNotify destroy)
+{
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ if (tree_view->priv->row_separator_destroy)
+ (* tree_view->priv->row_separator_destroy) (tree_view->priv->row_separator_data);
+
+ tree_view->priv->row_separator_func = func;
+ tree_view->priv->row_separator_data = data;
+ tree_view->priv->row_separator_destroy = destroy;
+}
+
+static gint
+check_expander_max (gint height,
+ gint expander_size,
+ GtkTreeView *tree_view,
+ GtkRBTree *tree,
+ GtkRBNode *node)
+{
+ if (height < expander_size)
+ {
+ gboolean is_separator = FALSE;
+
+ if (tree_view->priv->row_separator_func)
+ {
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ path = _gtk_tree_view_find_path (tree_view, tree, node);
+ gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
+ gtk_tree_path_free (path);
+
+ is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model,
+ &iter,
+ tree_view->priv->row_separator_data);
+ }
+
+ if (!is_separator)
+ g_warning ("height less than expander size;\n"
+ "please report this in http://bugzilla.gnome.org/show_bug.cgi?id=145528\n");
+ }
+
+ return height;
+}
+
+
const gchar *key,
GtkTreeIter *iter,
gpointer search_data);
+typedef gboolean (*GtkTreeViewRowSeparatorFunc) (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data);
/* Creators */
gboolean hover);
gboolean gtk_tree_view_get_hover_selection (GtkTreeView *tree_view);
+GtkTreeViewRowSeparatorFunc gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view);
+void gtk_tree_view_set_row_separator_func (GtkTreeView *tree_view,
+ GtkTreeViewRowSeparatorFunc func,
+ gpointer data,
+ GtkDestroyNotify destroy);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
cellview = gtk_cell_view_new ();
- store = gtk_list_store_new (2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
+ store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_BOOLEAN);
pixbuf = gtk_widget_render_icon (cellview, GTK_STOCK_DIALOG_WARNING,
GTK_ICON_SIZE_BUTTON, NULL);
gtk_list_store_set (store, &iter,
0, pixbuf,
1, "gtk-stock-dialog-warning",
+ 2, FALSE,
-1);
pixbuf = gtk_widget_render_icon (cellview, GTK_STOCK_STOP,
gtk_list_store_set (store, &iter,
0, pixbuf,
1, "gtk-stock-stop",
+ 2, FALSE,
-1);
pixbuf = gtk_widget_render_icon (cellview, GTK_STOCK_NEW,
gtk_list_store_set (store, &iter,
0, pixbuf,
1, "gtk-stock-new",
+ 2, FALSE,
-1);
pixbuf = gtk_widget_render_icon (cellview, GTK_STOCK_CLEAR,
gtk_list_store_set (store, &iter,
0, pixbuf,
1, "gtk-stock-clear",
+ 2, FALSE,
+ -1);
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ 0, NULL,
+ 1, "separator",
+ 2, TRUE,
+ -1);
+
+ pixbuf = gtk_widget_render_icon (cellview, GTK_STOCK_OPEN,
+ GTK_ICON_SIZE_BUTTON, NULL);
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ 0, pixbuf,
+ 1, "gtk-stock-open",
+ 2, FALSE,
-1);
gtk_widget_destroy (cellview);
path = gtk_tree_model_get_path (tree_model, iter);
indices = gtk_tree_path_get_indices (path);
-
- sensitive = indices[0] % 2;
+ sensitive = indices[0] != 1;
gtk_tree_path_free (path);
g_object_set (cell, "sensitive", sensitive, NULL);
renderer,
set_sensitive,
NULL, NULL);
- gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 1);
+ gtk_combo_box_set_row_separator_column (GTK_COMBO_BOX (combobox), 2);
+
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 0);
/* GtkComboBox (grid mode) */